package org.de.maeyer.statistic.view;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Set;
import java.util.Map.Entry;
import java.util.concurrent.Semaphore;

import org.apache.commons.collections.MultiMap;
import org.apache.commons.collections.map.MultiValueMap;
import org.de.maeyer.sampler.Sampler;
import org.de.maeyer.statistic.Statistics;
import org.de.maeyer.util.Pair;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.widgets.Shell;

/**
 * @author Peter De Maeyer
 */
public class SamplerMonitor extends Thread implements PaintListener {

	private final Shell shell;
	
	private final MultiMap viewsBySampler = new MultiValueMap();
	
	private volatile Collection<Pair<Statistics, View>> viewsByStatistic;
	
	private final Semaphore semaphore = new Semaphore(0);
	
	public SamplerMonitor(Shell shell) {
		super(SamplerMonitor.class.getName());
		this.shell = shell;
		this.shell.addPaintListener(this);
	}
	
	public synchronized void registerView(Sampler sampler, View view) {
		viewsBySampler.put(sampler, view);
	}

	@Override
	public void run() {
		System.out.println("Sampler monitor started.");
		while (!interrupted()) {
			Collection<Pair<Statistics, View>> newViewsByStatistic = new ArrayList<Pair<Statistics, View>>(viewsBySampler.size());
			synchronized (this) {
				Set entrySet = viewsBySampler.entrySet();
				for (Object entry: entrySet) {
					Entry e = (Entry) entry;
					Statistics statistics = ((Sampler) e.getKey()).getStatistics();
					if (statistics != null) {
						Collection views = (Collection) e.getValue();
						for (Object view: views) {
							newViewsByStatistic.add(new Pair<Statistics, View>(statistics, (View) view));
						}
					}
				}
			}
			viewsByStatistic = newViewsByStatistic;
			shell.getDisplay().asyncExec(new Runnable() {
				
				public void run() {
					if (!shell.isDisposed()) {
						shell.redraw();
					}
				}
			});
			try {
				semaphore.acquire();
			} catch (InterruptedException e) {
				break; // We've been interrupted.
			}
		}
		System.out.println("Sampler monitor stopped.");
	}

	public void paintControl(PaintEvent event) {
		Collection<Pair<Statistics, View>> viewsByStatistic = this.viewsByStatistic;
		semaphore.release();
		for (Pair<Statistics, View> view: viewsByStatistic) {
			view.second().paint(event, view.first());
		}
	}
}